======================================================================
                             GDF Routines
======================================================================

All gdf routines were written by Jim Meyer.

		Center for Morphometric Analysis
		Neuroscience Center
		Massachusetts General Hospital-East
		Building 149, 13th Street
		Charlestown MA  02129-2017  USA

Documentation History:
	AJW 	Created					Feb  7  1995	
	AJW 	Added table stuff			Jan 23  1996	

*********************************************************************
*								    *
* (c) Copyright 1994,1995  The General Hospital Corporation         *
*                      All Rights Reserved                          *
*                                                                   *
*********************************************************************
GENERAL 

GDF stands for Generic Data Format.  Use it by loading and writing gdf
files and then manipulating the data using the routines described
below.

GDF files have a main header that defines the defaults for the rest of
the file.  The rest of the file is made up of "blocks".  Each block has
a header and data.  The bulk of data should be stored in the data
portion of the blocks.  The header must contain information describing
the size and type of the bulk data, but can contain other associated
descriptors (e.g a label) for that block.  The programmer will usually
design the data structure such that information pertinent to the entire
series of data blocks is assigned to the main header and is absent in
the block headers. Information retrieval routines query the main header
after determining field is absent in the block header, so a specified
block header value overrides the main header value.  Headers are always
ascii, both in memory and on file. The data blocks are always non-ascii
in memory, but can be represented either as ascii or non-ascii on
file.

Here is an example (the gdf file is on the left and comments are on the
right):

GDF FILE VERSION3		|  Main header: version ID
START MAIN HEADER		|  Main header:
TYPE short			|  Main header: field 0
COL_NUM 2			|  Main header: field 1
ONUM 5				|  Main header: ...etc...
END MAIN HEADER			|  Main header:

START GDF HEADER		|  BLock 0 header:
ROW_NUM 248			|  Block 0 header: field 0
SEED 309 301			|  Block 0 header: field 1
LABEL Tumor Boundary		|  Block 0 header: ...etc...
END GDF HEADER			|  Block 0 header:

START POINTS			|  Block 0 data:
<data points>			|  Block 0 data: bulk data here
END POINTS			|  Block 0 data:

START GDF HEADER		|  BLock 1 header:
ROW_NUM 248			|  Block 1 header: field 0
SEED 309 301			|  Block 1 header: field 1
LABEL Tumor Boundary		|  Block 1 header: ...etc...
END GDF HEADER			|  Block 1 header:

START POINTS			|  Block 1 data:
<data points>			|  Block 0 data: bulk data here
END POINTS			|  Block 1 data:

START GDF HEADER		|  ...etc...

Header fields are stored as text and consist of:

	<field name> <field data>

All gdf files will have the following fields:

	TYPE <type>
	COL_NUM <int>
	ROW_NUM <int>

Bulk data <data points> are stored in a COL_NUM by ROW_NUM array and
have a <type> that can be any C data type:

        char
        short
        double
        float
        long
        unsigned char
        unsigned short  
	table		/* gdf specific type for using mulitple C data types */

NOTE: All numbers in gdf files are assumed to be big endian since gdf
was originally implemented on a Sun.  This means the most significant
byte of multiple-byte words are stored first (lower addresses).

----------------------------------------------------------------------
Access to GDF files
----------------------------------------------------------------------
GDF files are CREATED and allocated with:

	struct gdf_file *fi;

	fi_calloc(&fi);

GDF files are READ into memory with

	char   filnam[MAXPATHLEN];
	struct gdf_file *fi;

	fi_calloc(&fi);
        strcpy(filnam,"mygdf.file");
        if(read_gdf_file(filnam,fi)==-1) {
          fprintf(stderr,"couldn't open %s\n",filnam);
          } /* if */

	NOTE: read_gdf_file() will free any previous information in fi
		before loading in the new information.

GDF files are WRITTEN to disk with

	struct gdf_file *fi;

        wr_gdf_file("mygdf.file",fi);

The number of data blocks in a gdf file is

	struct gdf_file *fi;

	fi->num

A NEW data block can be ADDED by

	struct gdf_file *fi;

	add_block(fi,NULL,"<type>",cols,rows)

Existing data will be copied into a new data block by

	struct gdf_file *fi; 
	<type> *points;

	add_block(fi,points,"<type>",cols,rows)

----------------------------------------------------------------------
Access to Header fields
----------------------------------------------------------------------
add_* add fields

	struct gdf_file *fi; 
	int block_num;		/* block number 
				   (use MAIN for the main header) */
	char *field;		/* text name of field */

	char *value;
	double	doub,doub1,doub2,doub3,doub4;
	int	integ,integ1,integ2,integ3,integ4;

	add_string(fi,block_num,field,value)

	add_double(fi,block_num,field,doub)
	add_2double(fi,block_num,field,doub1,doub2)
	add_3double(fi,block_num,field,doub1,doub2,doub3)
	add_4double(fi,block_num,field,doub1,doub2,doub3,doub4)

	add_int(fi,block_num,field,integ)
	add_2int(fi,block_num,field,integ1,integ2)
	add_3int(fi,block_num,field,integ1,integ2,integ3)
	add_4int(fi,block_num,field,integ1,integ2,integ3,integ4)

----------------------------------------------------------------------
change_* change a field or adds a new one to the end

	change_double(fi,block_num,field,doub)
	change_2double(fi,block_num,field,doub1,doub2)
	change_3double(fi,block_num,field,doub1,doub2,doub3)
	change_4double(fi,block_num,field,doub1,doub2,doub3,doub4) 

	change_int(fi,block_num,field,integ)
	change_2int(fi,block_num,field,integ1,integ2)
	change_3int(fi,block_num,field,integ1,integ2,integ3)
	change_4int(fi,block_num,field,integ1,integ2,integ3,integ4)

----------------------------------------------------------------------
find_* return values from the specified block_number or from the MAIN
  header if this field is not present in the given block.

	int block_num,cls;
	char *valuep;
	double slth;

for one value:

	strcpy(valuep,find_string(fi,block_num,"<field name>"));
	cls = find_int(fi,block_num,COL_NUM);
	slth = find_double(fi,block_num,SL_THICK);

for more than one value:

	int	block_num;
	char	*field;
	int 	sizex,sizey;
	double	doub,doub1,doub2,doub3,doub4;
	int	integ,integ1,integ2,integ3,integ4;

	if(find_2int(fi,block_num,SIZE,&sizex,&sizey)!=2)
	  printf(stderr,"ERROR: find_2int(%d,SIZE) returned %d\n",
		block_num,rval");

	if(find_3int(fi,block_num,field,&int1,&int2,&int3)!=3)
	  printf(stderr,"ERROR: find_3int(%d,%s) returned %d\n",
		block_num,field,rval");

	if(find_4int(fi,block_num,field,&int1,&int2,&int3,&int4)!=4)
	  printf(stderr,"ERROR: find_4int(%d,%s) returned %d\n",
		block_num,field,rval");

	if(find_2double(fi,block_num,field,&doub1,&doub2)!=2)
	  printf(stderr,"ERROR: find_2double(%d,%s) returned %d\n",
		block_num,field,rval");

	if(find_3double(fi,block_num,field,&doub1,&doub2,&doub3)!=3)
	  printf(stderr,"ERROR: find_3double(%d,%s) returned %d\n",
		block_num,field,rval");

	if(find_4double(fi,block_num,field,&doub1,&doub2,&doub3,&doub4)!=4)
	  printf(stderr,"ERROR: find_3double(%d,%s) returned %d\n",
		block_num,field,rval");

----------------------------------------------------------------------
Access to bulk data
----------------------------------------------------------------------
A pointer to the data for block number block_num can be had with

	struct gdf_file *fi;
	int block_num;
	<type>	*p;

        p = (fi->pts+block_num)-><dp>;
or
	p = (<type> *)find_data(fi,block_num);

where the data pionter <dp> depends on the <type> of the data:

        <type>              <dp>
        -----------------   ----
        char                *cp;
        short               *sp;
        double              *dp;
        float               *fp;
        long                *lp;
        unsigned char       *ucp;
        unsigned short      *usp;
        struct pt           *ptp;
        union point_types   *unp;

----------------------------------------------------------------------
Access to tables
----------------------------------------------------------------------

A table is created with make_table(va_alist):

	struct gdf_file *fi;
	int		rows,cols
	make_table(fi,rows,cols,type1,type2,type3,...);

	   Where if typeN starts with a number it is a string with that
	   number of charactes otherwise, it is one of the <type>s as a
	   string ("int", "double", etc).

e.g.

	struct gdf_file *fi;

	  make_table(fi,1,4,"35s","double","double","double");

Rows are added to the table using:

	struct gdf_file *fi;
	int onum;

	add_row(fi,onum);

and then the information is added to that row using table_pointer():

e.g.
	struct gdf_file *fi;
	int onum,i;
	char *field;
	double dvar;

	i = find_int(fi,onum,ROW_NUM) - 1;
	strcpy((char *)table_pointer(fi,onum,0,i),field);  /* for a string */
        *((double *)table_pointer(fi,onum,1,0)+i) = dvar;  /* for a double */

The routine add_info_point() in info_point.c gives an example of
creating and adding rows to a table.

Adding a column is done by:

	struct gdf_file *fi;
	int	onum;
	char	*type,*label,*format;

	add_column(fi,onum,type,label,format)

e.g.
	add_column(fi_prcunits,0,"short","rant val",NULL);

find_column_number(line,name)
find_column_name(line,col_num)
rm_table_info(temp,column_to_rm)

----------------------------------------------------------------------
Miscellaneous gdf commands and capabilities
----------------------------------------------------------------------
Editing GDF files as text
You can create gdf files using a text editor.  Here's how... (help!)


----------------------------------------------------------------------
GDF Routines
----------------------------------------------------------------------

add_block.c
----------------------------------------------------------------------
add_block(fi,points,type,cols,rows)

add_column.c
----------------------------------------------------------------------
add_column(fi,onum,type,label,format)

add_field.c
----------------------------------------------------------------------
add_field(va_alist)
add_string(file_info,num,field,value)

add_point.c
----------------------------------------------------------------------
add_point(va_alist)

add_row.c
----------------------------------------------------------------------
add_row(fi,onum)

change_field.c
----------------------------------------------------------------------
change_field(va_alist)
change_string(file_info,num,field,value)

check_field.c
----------------------------------------------------------------------
check_field(va_alist)

cma_data.c
----------------------------------------------------------------------
read_otl(fi,pid,scn,pre,slice) 
write_otl(fi,pid,scn,pre,slice) 
write_nvol(fi,pid,scn,pre) 
read_nvol(fi,pid,scn,pre)
read_info_file(fi,pid,scn)
write_info_file(fi,pid,scn)

cma_util.c
----------------------------------------------------------------------
get_date(file_name)
norm_status(file_name)
info_file_status(file_name)
interpolate_points(pts,x1,y1,x2,y2)
double distance(x1,y1,x2,y2)
double distance_3d(xp1,yp1,zp1,xp2,yp2,zp2,xdm,ydm,zdm)
double angle(x1,y1,x2,y2)
void scale_points(pts_in,pts_out,num,scale)
void scale_points2(pts_in,pts_out,num,scale_x,scale_y,orig_x,orig_y)
void shift_points(pts_in,pts_out,num,xoff,yoff)
int get_com(pts,num,cx,cy)
match_point(pts,num,x,y)
get_extents(pts,num,xmin,xmax,ymin,ymax)
strip_rl(label_in,label_out)
swap_rl(label_in,label_out)

copy_file.c
----------------------------------------------------------------------
copy_file(fi1,fi2)

cp_block.c
----------------------------------------------------------------------
cp_block(fi_to,fi_from,index)

fac.c
----------------------------------------------------------------------
find_int(fi,onum,field)
find_2int(fi,onum,field,int1,int2)
find_3int(fi,onum,field,int1,int2,int3)
find_4int(fi,onum,field,int1,int2,int3,int4)
find_double(fi,onum,field)
find_2double(fi,onum,field,doub1,doub2)
find_3double(fi,onum,field,doub1,doub2,doub3)
find_4double(fi,onum,field,doub1,doub2,doub3,doub4)
add_double(fi,onum,field,doub)
add_2double(fi,onum,field,doub1,doub2)
add_3double(fi,onum,field,doub1,doub2,doub3)
add_4double(fi,onum,field,doub1,doub2,doub3,doub4)
add_int(fi,onum,field,integ)
add_2int(fi,onum,field,integ1,integ2)
add_3int(fi,onum,field,integ1,integ2,integ3)
add_4int(fi,onum,field,integ1,integ2,integ3,integ4)
change_double(fi,onum,field,doub)
change_2double(fi,onum,field,doub1,doub2)
change_3double(fi,onum,field,doub1,doub2,doub3)
change_4double(fi,onum,field,doub1,doub2,doub3,doub4) 
change_int(fi,onum,field,integ)
change_2int(fi,onum,field,integ1,integ2)
change_3int(fi,onum,field,integ1,integ2,integ3)
change_4int(fi,onum,field,integ1,integ2,integ3,integ4)
de_zerodoub(doub)
de_zero2doub(doub1,doub2)
de_zero3doub(doub1,doub2,doub3)
de_zero4doub(doub1,doub2,doub3,doub4)
find_string(fi,onum,field)
find_data(fi,onum)
find_otl(fi,onum,pts,num)

find_field.c
----------------------------------------------------------------------
find_field(file_info,num,field)

free_file.c
----------------------------------------------------------------------
free_file(fi)

gdf_random.c
----------------------------------------------------------------------
get_seed_point(fi,onum) - given an outline, return a valid seed for it.
reverse_order(fi)
gdf_extents(fi,onum,xmin,xmax,ymin,ymax,update_flg)
gdf_com(fi,onum,xcm,ycm)
gdf_area(fi,onum,update_flag)
eliminate_red_points(fi,onum)

gdflib.c
----------------------------------------------------------------------
void put_point_values(fi,onum,grid,inten_val,offset)
void draw_lines(fi,onum,grid,fval)
void insert_outline(pts1,num1,pts2,num2,pts3,num3)
int make_map(fi,onum,grid,fval,code,user_func)
int ovl_to_otl(fi_otl,fi_ovl,onum,threshold)
int otl_to_ovl(fi_ovl,fi_otl,onum)
int map_to_otl(map,sizex,sizey,fi_otl,extraction_order,extraction_num,innards_flg)
int map_to_ovl(fi_map,map_index,fi_ovl)
int gdf_edgext(grid,seed_x,seed_y,fi_otl,border_or_not,innards_flg)
unsigned char * get_point_values(fi,onum,grid)
int	default_fill(),default_extract(),default_extract_inv(); 
int        UCfill_num,fill_only_me,fill_only_me_func();
draw_lines(fi,onum,grid,fval)
get_point_values(fi,onum,grid)
put_point_values(fi,onum,grid,inten_val,offset)
make_map(fi,onum,grid,fval,code,user_func)
ovl_to_otl(fi_otl,fi_ovl,onum,threshold)
otl_to_ovl(fi_ovl,fi_otl,onum)
gdf_edgext(grid,seed_x,seed_y,fi_otl,border_or_not,innards_flg)
closest_point(pts1,num1,pts2,num2,num3,num4)
int     extract_all_but_me,extract_all_but_me_func();
extract_all_but_me_func(val,x,y)
which_comes_first(extraction_order,extraction_num,val1,val2)

map_to_otl() - 

map_to_ovl(fi_map,map_index,fi_ovl)
fill_only_me_func(val,x,y)
smooth_map(map,sizex,sizey,threshold)

get_aline.c
----------------------------------------------------------------------
get_aline(cp)

grab_field.c
----------------------------------------------------------------------
grab_field(file_info,num,field)

happy_order.c
----------------------------------------------------------------------
char *get_cortical_label();
get_number_of_parcunits()
get_cortical_id(label)
get_cortical_label(val)

info_gdf.c
----------------------------------------------------------------------
find_xyzdim(fi,onum,xdim,ydim,zdim)
find_ipres(fi,onum,ipx,ipy,slth)
read_image_data(fi_in,fi_data)

info_point.c
----------------------------------------------------------------------
find_info_point(fi,onum,field,cord)
add_info_point(fi,onum,field,cord)
change_info_point(fi,onum,field,cord) 

make_otl_data.c
----------------------------------------------------------------------
make_otl_data(file_info,header,onum)

make_table.c
----------------------------------------------------------------------
make_table(va_alist)
ascii_default_width(data_type)
find_column_number(line,name)
find_column_name(line,col_num)
rm_table_info(temp,column_to_rm)

mcalloc.c
----------------------------------------------------------------------
fi_calloc(fi)
malloc_or_die(size)
free_if_need(pointer)
mcalloc_die(pointer)

merge_file.c
- this mergest gdf file fi2 into gdf file fi1.  The resulting main
header will be the amin header from fi1 plus any fields from fi2
which did not exist in fi1.
----------------------------------------------------------------------
merge_file(fi1,fi2)

mv_block.c
----------------------------------------------------------------------
mv_block(fi_to,fi_from,index)

next_field.c
----------------------------------------------------------------------
/* next_field(fi,num,style,field, ... , ... , "") */
int next_field(va_alist)

query_field.c
----------------------------------------------------------------------
query_field(field)

query_size.c
----------------------------------------------------------------------
query_size(type)

read_gdf_file.c
----------------------------------------------------------------------
int read_gdf_file(filnam,file_info)

read_pts.c
----------------------------------------------------------------------
read_pts(file_info,points,onum)

rm_block.c
----------------------------------------------------------------------
rm_block(fi,onum)

rm_column.c
----------------------------------------------------------------------
rm_column(fi,onum,column_to_rm)

rm_field.c
----------------------------------------------------------------------
rm_field(file_info,num,field)

strip_file.c
----------------------------------------------------------------------
strip_file(file_in,file_out,line_between_blocks)

table_pointer.c
----------------------------------------------------------------------
table_pointer(fi,onum,col,row)

wr_file_head.c
----------------------------------------------------------------------
wr_file_head(va_alist)

wr_gdf_excel.c
----------------------------------------------------------------------
wr_gdf_excel(filnam,file_info,sep_char)
write_excel_points(fpo,pts,type,dim,num,sep_char)

wr_gdf_file.c
----------------------------------------------------------------------
wr_gdf_file(filnam,file_info)

wr_gdf_head.c
----------------------------------------------------------------------
wr_gdf_head(va_alist)

write_points.c
----------------------------------------------------------------------

UClib.c
----------------------------------------------------------------------
write_points(fpo,pts,type,dim,num)
UCRectangle(grid,sizex,sizey,stx,sty,widthx,widthy,fval)
UCCopy_Section(gridto,ssx,ssy,gridfrom,bsx,bsy,startx,starty,widthx,widthy)  
UCCopy(gridto,gridfrom,sizex,sizey,stx,sty,widthx,widthy)  
UCDrawLine(grid,sizex,sizey,fval,x1,y1,x2,y2)
int UCFill(grid,sizex,sizey,seed_x,seed_y,fval,fill_or_not)
int default_fill(val,x,y)
int default_extract(val,x,y)
int default_extract_inv(val,x,y)
int UCEdgext(grid,sizex,sizey,seed_x,seed_y,pts,num,border_or_not)
static point(x,y,pts,num,first_x,first_y,attempts)